package com.closer.server.biz.problem.validator;

import cn.dev33.satoken.stp.StpUtil;
import com.closer.server.biz.problem.dto.*;
import com.closer.server.biz.problem.dto.SearchByAdminRequest;
import com.closer.server.biz.problem.enums.LanguageEnum;
import com.closer.server.mapper.problem.ProblemMapper;
import com.closer.server.mapper.user.UserMapper;
import com.closer.server.support.exception.ErrorCode;
import com.closer.server.support.exception.ThrowUtils;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.List;

@Component
public class ProblemValidator {

    private final UserMapper userMapper;

    private final ProblemMapper problemMapper;

    public ProblemValidator(UserMapper userMapper, ProblemMapper problemMapper) {

        this.userMapper = userMapper;
        this.problemMapper = problemMapper;
    }

    /**
     * 验证添加题目参数
     * @param params 添加题目参数
     */
    public void validate(AddRequest params) {
        validateExitUser(params.getCreatedUserId());
        baseValidate(params.getTitle(), params.getDescription(), params.getDifficulty(),
                params.getJudgeConfig(), params.getInputDescription(), params.getOutputDescription(),
                params.getSampleInput(), params.getSampleOutput(), params.getHint(), params.getJudgeCases());
    }

    /**
     * 验证搜索题目参数
     * @param params 搜索题目参数
     */
    public void validate(SearchRequest params) {
        if (params.getTitle() != null) {
            ThrowUtils.throwIf(params.getTitle().length() > 255, ErrorCode.PARAMS_ERROR, "标题长度不能超过255");
        }
        if(params.getDifficulty() != null){
            ThrowUtils.throwIf(!(params.getDifficulty() >= 0 && params.getDifficulty() <= 2), ErrorCode.PARAMS_ERROR, "难度参数错误");
        }
    }

    /**
     * 验证更新题目参数
     * @param params 更新题目参数
     */
    public void validate(UpdateRequest params) {
        validateExitProblem(params.getProblemId());
        baseValidate(params.getTitle(), params.getDescription(), params.getDifficulty(),
                params.getJudgeConfig(), params.getInputDescription(), params.getOutputDescription(),
                params.getSampleInput(), params.getSampleOutput(), params.getHint(), params.getJudgeCases());

    }

    /**
     * 验证提交题目参数
     * @param problemId 题目Id
     * @param code      代码
     * @param language  语言
     */
    public void validate(Long problemId,String code,String language,Long userId){
        ThrowUtils.throwIf(!StpUtil.isLogin(),ErrorCode.NOT_LOGIN_ERROR,"用户未登录");
        validateExitProblem(problemId);
        validateExitUser(userId);
        validateCode(code);
        ThrowUtils.throwIf(LanguageEnum.getEnumByValue(language)==null,ErrorCode.PARAMS_ERROR,"语言参数错误");

    }

    /**
     * 验证搜索题目参数[管理员]
     * @param params 搜索题目参数
     */
    public void validate(SearchByAdminRequest params) {
        if (params.getTitle() != null) {
            ThrowUtils.throwIf(params.getTitle().length() > 255, ErrorCode.PARAMS_ERROR, "标题长度不能超过255");
        }
        if(params.getDifficulty() != null){
            ThrowUtils.throwIf(!(params.getDifficulty() >= 0 && params.getDifficulty() <= 2), ErrorCode.PARAMS_ERROR, "难度参数错误");
        }
        if (params.getVisible() != null){
            ThrowUtils.throwIf(!(params.getVisible() >= 0 && params.getVisible() <= 1), ErrorCode.PARAMS_ERROR, "可见参数错误");
        }
        if (params.getCreatedUserId() != null){
            ThrowUtils.throwIf(params.getCreatedUserId() <= 0, ErrorCode.PARAMS_ERROR, "用户Id错误");
            ThrowUtils.throwIf(userMapper.getUserInfoById(params.getCreatedUserId()) == null, ErrorCode.PARAMS_ERROR, "用户不存在");
        }
    }

    private void baseValidate(String title, String description, Integer difficulty,
                              JudgeConfig judgeConfig, String inputDescription, String outputDescription,
                              String sampleInput, String sampleOutput, String hint, List<JudgeCase> judgeCases) {
        validateTitle(title);
        validateDescription(description);
        validateDifficulty(difficulty);
        validateJudgeConfig(judgeConfig);
        validateInputDescription(inputDescription);
        validateOutputDescription(outputDescription);
        validateSampleInput(sampleInput);
        validateSampleOutput(sampleOutput);
        validateHint(hint);
        validateJudgeCases(judgeCases);
    }

    /**
     * 验证标题
     * @param title 标题
     */
    public void validateTitle(String title){
        ThrowUtils.throwIf(title == null, ErrorCode.PARAMS_ERROR, "标题不能为空");
        ThrowUtils.throwIf(title.length() >255 , ErrorCode.PARAMS_ERROR, "标题长度不能超过255");
    }

    /**
     * 验证题目描述
     * @param description 题目描述
     */
    public void validateDescription(String description){
        ThrowUtils.throwIf(description == null, ErrorCode.PARAMS_ERROR, "题目描述不能为空");
        ThrowUtils.throwIf(description.length() >1024 , ErrorCode.PARAMS_ERROR, "题目描述长度不能超过1024");
    }
    /**
     * 验证题目难度
     * @param difficulty 难度
     */
    public void validateDifficulty(Integer difficulty){
        ThrowUtils.throwIf(difficulty == null, ErrorCode.PARAMS_ERROR, "难度不能为空");
        ThrowUtils.throwIf(!(difficulty >= 0 && difficulty <= 2), ErrorCode.PARAMS_ERROR, "难度参数错误");
    }
    /**
     * 验证判题配置
     * @param judgeConfig 判题配置
     */
    public void validateJudgeConfig(JudgeConfig judgeConfig){
        ThrowUtils.throwIf(judgeConfig == null, ErrorCode.PARAMS_ERROR, "判题配置不能为空");
        ThrowUtils.throwIf(judgeConfig.getTimeLimit() == null || judgeConfig.getTimeLimit() <= 0, ErrorCode.PARAMS_ERROR, "时间限制不能小于0");
        ThrowUtils.throwIf(judgeConfig.getMemoryLimit() == null || judgeConfig.getMemoryLimit() <= 0, ErrorCode.PARAMS_ERROR, "内存限制不能小于0");
    }

    /**
     * 验证输入描述
     * @param inputDescription 输入描述
     */
    public void validateInputDescription(String inputDescription){
        ThrowUtils.throwIf(inputDescription == null, ErrorCode.PARAMS_ERROR, "输入描述不能为空");
        ThrowUtils.throwIf(inputDescription.length() >1024 , ErrorCode.PARAMS_ERROR, "输入描述长度不能超过1024");
    }
    /**
     * 验证输出描述
     * @param outputDescription 输出描述
     */
    public void validateOutputDescription(String outputDescription){
        ThrowUtils.throwIf(outputDescription == null, ErrorCode.PARAMS_ERROR, "输出描述不能为空");
        ThrowUtils.throwIf(outputDescription.length() >1024 , ErrorCode.PARAMS_ERROR, "输出描述长度不能超过1024");
    }

    /**
     * 验证样例输入
     * @param sampleInput 样例输入
     */
    public void validateSampleInput(String sampleInput){
        if (sampleInput != null){
            ThrowUtils.throwIf(sampleInput.length() >1024 , ErrorCode.PARAMS_ERROR, "样例输入长度不能超过1024");
        }
    }

    /**
     * 验证样例输出
     * @param sampleOutput 样例输出
     */
    public void validateSampleOutput(String sampleOutput){
        if (sampleOutput != null){
            ThrowUtils.throwIf(sampleOutput.length() >1024 , ErrorCode.PARAMS_ERROR, "样例输出长度不能超过1024");
        }
    }

    /**
     * 验证题目提示
     * @param hint 提示
     */
    public void validateHint(String hint){
        if (hint != null){
            ThrowUtils.throwIf(hint.length() >1024 , ErrorCode.PARAMS_ERROR, "提示长度不能超过1024");
        }
    }

    /**
     * 验证判题用例
     * @param judgeCases 判题用例
     */
    public void validateJudgeCases(List<JudgeCase> judgeCases){
        ThrowUtils.throwIf(judgeCases == null, ErrorCode.PARAMS_ERROR, "判题用例不能为空");
        for (JudgeCase judgeCase : judgeCases) {
            var input = judgeCase.getInput();
            var output = judgeCase.getOutput();
            if(input!= null){
                ThrowUtils.throwIf(input.length() >1024 , ErrorCode.PARAMS_ERROR, "判题用例输入长度不能超过1024");
            }
           if (output!= null){
               ThrowUtils.throwIf(output.length() >1024 , ErrorCode.PARAMS_ERROR, "判题用例输出长度不能超过1024");
           }
        }
    }

    public void validateCode(String code){
        ThrowUtils.throwIf(code == null, ErrorCode.PARAMS_ERROR, "代码不能为空");
        var blackCodeList = new ArrayList<String>();
        blackCodeList.add("Files");
        blackCodeList.add("File");
        blackCodeList.add("FileInputStream");
        blackCodeList.add("FileOutputStream");
        blackCodeList.add("RandomAccessFile");
        ThrowUtils.throwIf(blackCodeList.contains(code),ErrorCode.OPERATION_ERROR,"代码中包含敏感词");
    }

    /**
     * 验证用户是否存在
     * @param userId 用户ID
     */
    public void validateExitUser(Long userId){
        ThrowUtils.throwIf(userId == null, ErrorCode.PARAMS_ERROR, "用户ID不能为空");
        ThrowUtils.throwIf(!StpUtil.isLogin(), ErrorCode.OPERATION_ERROR,"用户未登录");
        var user = userMapper.getUserInfoById(userId);
        ThrowUtils.throwIf(user == null, ErrorCode.PARAMS_ERROR, "用户不存在");
    }

    /**
     * 验证题目是否存在
     * @param problemId 题目ID
     */
    public void validateExitProblem(Long problemId){
        ThrowUtils.throwIf(problemId == null, ErrorCode.PARAMS_ERROR, "题目ID不能为空");
        ThrowUtils.throwIf(problemId<=0, ErrorCode.PARAMS_ERROR, "题目ID不能小于0");
        var question = problemMapper.selectOneById(problemId);
        ThrowUtils.throwIf(question == null, ErrorCode.PARAMS_ERROR, "题目不存在");
    }
}
